#ifndef _DEMUX_AVI_H_
#define _DEMUX_AVI_H_

#include "def.h"
#include "porting.h"
#include "_video.h"

#define AVIF_HASINDEX			0x00000010
#define AVIF_MUSTUSEINDEX		0x00000020
#define AVIF_ISINTERLEAVED		0x00000100
#define AVIF_TRUSTCKTYPE		0x00000800
#define AVIF_WASCAPTUREFILE		0x00010000
#define AVIF_COPYRIGHTED		0x00020000

#define AVI_MAX_RIFF_SIZE		0x40000000LL
#define AVI_MAX_STREAM_COUNT	100

#define AVISF_VIDEO_PALCHANGES	0x00010000

#define AVIIF_LIST				0x00000001
#define AVIIF_KEYFRAME			0x00000010
#define AVIIF_INDEX				0x00000010
#define AVIIF_FIRSTPART			0x00000020
#define AVIIF_LASTPART			0x00000040
#define AVIIF_NOTIME			0x00000100
#define AVIIF_COMPUSE			0x0fff0000

typedef enum {
	AVI_OK = 0,
	AVI_RIFF_ERR,
	AVI_AVI_ERR,
	AVI_LIST_ERR,
	AVI_HDRL_ERR,
	AVI_AVIH_ERR,
	AVI_STRL_ERR,
	AVI_STRH_ERR,
	AVI_STRF_ERR,
	AVI_MOVI_ERR,
	AVI_JUNK_ERR,
	AVI_FORMAT_ERR,
	AVI_STREAM_ERR,
	AVI_STREAM_OVER,
	AVI_IX00,
	AVI_IDX1,
}AVISTATUS;


#define AVI_RIFF_ID			0X46464952	//RIFF
#define AVI_AVI_ID			0X20495641	//AVI
#define AVI_LIST_ID			0X5453494C	//LIST
#define AVI_HDRL_ID			0X6C726468	//hdrl
#define AVI_STRL_ID			0X6C727473	//strl
#define AVI_MOVI_ID			0X69766F6D	//movi
#define AVI_AVIH_ID			0X68697661	//avih
#define AVI_STRH_ID			0X68727473	//strh
#define AVI_STRF_ID			0X66727473	//strf
#define AVI_STRD_ID			0X64727473	//strd
#define AVI_VIDS_ID			0X73646976	//vids
#define AVI_AUDS_ID			0X73647561	//auds
#define AVI_JUNK_ID			0X4B4E554A	//JUNK
#define AVI_00DB_ID			0X62643030	//00db
#define AVI_01DB_ID			0X62643130	//01db
#define AVI_00DC_ID			0X63643030	//00dc
#define AVI_01DC_ID			0X63643130	//01dc
#define AVI_00WB_ID			0X62773030	//00wb
#define AVI_01WB_ID			0X62773130	//01wb
#define AVI_IX00_ID			0x30307869	//ix00
#define AVI_IX01_ID			0x31307869	//ix01
#define AVI_IDX0_ID			0X30786469	//idx0
#define AVI_IDX1_ID			0X31786469	//idx1
#define AVI_MJPG_ID			0X47504A4D	//MJPG
#define AVI_H264_ID			0X34363248	//H264

#define AVI_VIDS_FLAG0		AVI_00DC_ID
#define AVI_VIDS_FLAG1		AVI_01DC_ID
#define AVI_AUDS_FLAG0		AVI_00WB_ID
#define AVI_AUDS_FLAG1		AVI_01WB_ID

#define AVI_FORMAT_MJPG		AVI_MJPG_ID
#define AVI_FORMAT_H264		AVI_H264_ID


typedef union
{
	u32 id;
	char ch[4];
}FCC;

typedef struct
{
	FCC fccid;
	u32 size;
	FCC fcctype;
}CHUNK_HEADER;

typedef struct
{
	FCC fccid;
	u32 size;
}ITEM_HEADER;

typedef struct
{
	u32 dwMicroSecPerFrame;
	u32 dwMaxBytesPerSec;
	u32 dwReserved1; //PaddingGranularity;
	u32 dwFlags;
	u32 dwTotalFrames;
	u32 dwInitialFrames;
	u32 dwStreams;
	u32 dwSuggestedBufferSize;
	u32 dwWidth;
	u32 dwHeight;
	u32 dwScale;
	u32 dwRate;
	u32 dwStart;
	u32 dwLength;
}MainAVIHeader;

typedef struct
{
	ITEM_HEADER avih;
	MainAVIHeader mainaviheader;
}AVI_HEADER;

typedef struct
{
	u32 biSize;
	int biWidth;
	int biHeight;
	u16 biPlanes;
	u16 biBitCount;
	u32 biCompression;
	u32 biSizeImage;
	int biXPelsPerMeter;
	int biYPelsPerMeter;
	u32 biClrUsed;
	u32 biClrImportant;
} BitmapInfoHeader;

typedef struct
{
	u16 wFormatTag;
	u16 nChannels;
	u32 nSamplesPerSec;
	u32 nAvgBytesPerSec;
	u16 nBlockAlign;
	u16 wBitsPerSample;
	u16 cbSize;
	u16	Reserve1;
	u16	Reserve2;
	u16	Reserve3;
	u32	Reserve4;
	u32	Reserve5;
} ExternWavFotmat;

typedef struct
{
	FCC fccHandler;
	u32 dwFlags;
	u32 dwReserved1;	// u16 Priority;	u16 Language;
	u32 dwInitialFrames;
	u32 dwScale;
	u32 dwRate;
	u32 dwStart;
	u32 dwLength;
	u32 dwSuggestedBufferSize;
	u32 dwQuality;
	u32 dwSampleSize;
	union
	{
		struct
		{
			short Left;
			short Top;
			short Right;
			short Bottom;
		}v;
		struct
		{
			u32 dwReserved2;
			u32 dwReserved3;
		}a;
	}u;
}AVIStreamHeader;

typedef struct
{
	ITEM_HEADER h;
	u32 unknow1;
	u32 unknow2;
	FCC fccFlagTag;
	u8  dwReserved3[0x1018-12];
}JUNK, STRD, STRN, INDX;

typedef struct
{
	CHUNK_HEADER chunk_strl;
	CHUNK_HEADER strh_vids;
	AVIStreamHeader vids_header;
	ITEM_HEADER item_strf;
	BitmapInfoHeader bmpinfo;
	JUNK junk;
	//STRD strd;
	//STRN strn;
	//INDX strx;
}VIDS_STRL;

typedef struct
{
	CHUNK_HEADER chunk_strl;
	CHUNK_HEADER strh_auds;
	AVIStreamHeader auds_header;
	ITEM_HEADER item_strf;
	ExternWavFotmat wavformat;
	JUNK junk;
	//STRD strd;
	//STRN strn;
	//INDX strx;
}AUDS_STRL;

typedef struct
{
	CHUNK_HEADER chunk_RIFF;
	CHUNK_HEADER chunk_hdrl;
	AVI_HEADER avi_header;
	VIDS_STRL vids_strl;
	AUDS_STRL auds_strl;

	CHUNK_HEADER chunk_movi;
	//......
	ITEM_HEADER item_idx1;
	//......
}AVI_FILE_MAP;

typedef struct
{
	DWORD ckid;
	DWORD dwFlags;//AVIIF_KEYFRAME;AVIIF_LIST;AVIIF_FIRSTPART;AVIIF_LASTPART;AVIIF_NOTIME
	DWORD dwChunkOffset;
	DWORD dwChunkLength;
}AVIINDEXENTRY;

typedef struct
{
	ITEM_HEADER h;
	void* buff;
	FSIZE_t offset;
}FRAME;

typedef struct
{
	AVI_FILE_MAP avi_file_map;

	FSIZE_t hdrl_offset;
	FSIZE_t hdrl_len;
	FSIZE_t movi_offset;
	FSIZE_t movi_len;
	FSIZE_t idx1_offset;
	FSIZE_t idx1_len;

	u32 TotalFrame;
	u32 Width;
	u32 Height;
	u32 VideoType;
	u32 VideoFLAG;
	u32 SampleRate;
	u32 Channels;
	u32 AudioFLAG;
	u32 AudioType;

	FRAME frame_a;
	FRAME frame_v;
}AVI_CONTEXT;

VIDEO_ERROR avi_init();
VIDEO_ERROR avi_free();
void avi_config();

AVISTATUS avi_get_avi_info(FIL* favi);

AVISTATUS avi_get_hdrl_offset(FIL* favi);
AVISTATUS avi_get_movi_offset(FIL* favi);
AVISTATUS avi_get_idx1_offset(FIL* favi);
AVISTATUS avi_get_idx1_info(FIL* favi);

AVISTATUS avi_seek_to_movi(FIL* favi);

VIDEO_ERROR avi_get_block_head(FIL* favi, ITEM_HEADER* h);
VIDEO_ERROR avi_get_block_data(FIL* favi, void* data, u32 len);

void avi_update_file_map(FIL* favi);

VIDEO_ERROR avi_put_avi_info(FIL* favi);

VIDEO_ERROR avi_put_block_head(FIL* favi, ITEM_HEADER* h);
VIDEO_ERROR avi_put_block_data(FIL* favi, void* data, u32 len);

VIDEO_ERROR avi_put_idx1_info(FIL* favi);
VIDEO_ERROR avi_ensure_alignment(FIL* favi);

extern AVI_CONTEXT* g_avi_context;

#endif
